<!doctype html>



  


<html class="theme-next mist use-motion">
<head>
  <meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>



<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />












  <link href="/vendors/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css"/>




  <link href="//fonts.googleapis.com/css?family=Lato:300,400,700,400italic&subset=latin,latin-ext" rel="stylesheet" type="text/css">



<link href="/vendors/font-awesome/css/font-awesome.min.css?v=4.4.0" rel="stylesheet" type="text/css" />

<link href="/css/main.css?v=0.5.0" rel="stylesheet" type="text/css" />


  <meta name="keywords" content="Hexo, NexT" />





  <link rel="alternate" href="/atom.xml" title="Zhangzju`s blog" type="application/atom+xml" />




  <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico?v=0.5.0" />






<meta name="description" content="A man can be destroyed but not defeated.">
<meta property="og:type" content="website">
<meta property="og:title" content="Zhangzju`s blog">
<meta property="og:url" content="http://yoursite.com/index.html">
<meta property="og:site_name" content="Zhangzju`s blog">
<meta property="og:description" content="A man can be destroyed but not defeated.">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Zhangzju`s blog">
<meta name="twitter:description" content="A man can be destroyed but not defeated.">



<script type="text/javascript" id="hexo.configuration">
  var NexT = window.NexT || {};
  var CONFIG = {
    scheme: 'Mist',
    sidebar: {"position":"left","display":"post"},
    fancybox: true,
    motion: true,
    duoshuo: {
      userId: 0,
      author: '博主'
    }
  };
</script>

  <title> Zhangzju`s blog </title>
</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">

  








  
  
    
  

  <div class="container one-collumn sidebar-position-left 
   page-home 
 ">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-meta ">
  

  <div class="custom-logo-site-title">
    <a href="/"  class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <span class="site-title">Zhangzju`s blog</span>
      <span class="logo-line-after"><i></i></span>
    </a>
  </div>
  <p class="site-subtitle">Javascript everywhere!</p>
</div>

<div class="site-nav-toggle">
  <button>
    <span class="btn-bar"></span>
    <span class="btn-bar"></span>
    <span class="btn-bar"></span>
  </button>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu ">
      
        
        <li class="menu-item menu-item-home">
          <a href="/" rel="section">
            
              <i class="menu-item-icon fa fa-home fa-fw"></i> <br />
            
            首页
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/archives" rel="section">
            
              <i class="menu-item-icon fa fa-archive fa-fw"></i> <br />
            
            归档
          </a>
        </li>
      
        
        <li class="menu-item menu-item-tags">
          <a href="/tags" rel="section">
            
              <i class="menu-item-icon fa fa-tags fa-fw"></i> <br />
            
            标签
          </a>
        </li>
      

      
      
      
    </ul>
  

  
</nav>

 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            
  <section id="posts" class="posts-expand">

    

    
    

    
      

  
  

  
  
  

  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
            
            
              
                
                <a class="post-title-link" href="/2016/02/21/hello-world/" itemprop="url">
                  Hello World
                </a>
              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">
            <span class="post-meta-item-icon">
              <i class="fa fa-calendar-o"></i>
            </span>
            <span class="post-meta-item-text">发表于</span>
            <time itemprop="dateCreated" datetime="2016-02-21T21:32:20+08:00" content="2016-02-21">
              2016-02-21
            </time>
          </span>

          

          
            
              <span class="post-comments-count">
                &nbsp; | &nbsp;
                <a href="/2016/02/21/hello-world/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count ds-thread-count" data-thread-key="2016/02/21/hello-world/" itemprop="commentsCount"></span>
                </a>
              </span>
            
          

          

          
          
        </div>
      </header>
    


    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <p>Welcome to <a href="http://hexo.io/" target="_blank" rel="external">Hexo</a>! This is your very first post. Check <a href="http://hexo.io/docs/" target="_blank" rel="external">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="http://hexo.io/docs/troubleshooting.html" target="_blank" rel="external">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues" target="_blank" rel="external">GitHub</a>.</p>
<h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo new <span class="string">"My New Post"</span></span><br></pre></td></tr></table></figure>
<p>More info: <a href="http://hexo.io/docs/writing.html" target="_blank" rel="external">Writing</a></p>
<h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo server</span><br></pre></td></tr></table></figure>
<p>More info: <a href="http://hexo.io/docs/server.html" target="_blank" rel="external">Server</a></p>
<h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo generate</span><br></pre></td></tr></table></figure>
<p>More info: <a href="http://hexo.io/docs/generating.html" target="_blank" rel="external">Generating</a></p>
<h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo deploy</span><br></pre></td></tr></table></figure>
<p>More info: <a href="http://hexo.io/docs/deployment.html" target="_blank" rel="external">Deployment</a></p>

          
        
      
    </div>

    <footer class="post-footer">
      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </article>


    
      

  
  

  
  
  

  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
            
            
              
                
                <a class="post-title-link" href="/2016/02/21/Node.js的并发控制浅析/" itemprop="url">
                  Node.js的并发控制浅析
                </a>
              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">
            <span class="post-meta-item-icon">
              <i class="fa fa-calendar-o"></i>
            </span>
            <span class="post-meta-item-text">发表于</span>
            <time itemprop="dateCreated" datetime="2016-02-21T21:31:27+08:00" content="2016-02-21">
              2016-02-21
            </time>
          </span>

          

          
            
              <span class="post-comments-count">
                &nbsp; | &nbsp;
                <a href="/2016/02/21/Node.js的并发控制浅析/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count ds-thread-count" data-thread-key="2016/02/21/Node.js的并发控制浅析/" itemprop="commentsCount"></span>
                </a>
              </span>
            
          

          

          
          
        </div>
      </header>
    


    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h1 id="Node-js的并发控制浅析"><a href="#Node-js的并发控制浅析" class="headerlink" title="Node.js的并发控制浅析"></a>Node.js的并发控制浅析</h1><p>@(Node.js)[并发|eventproxy|async|promise]</p>
<p>Nodejs是运行在chromeV8上的<strong>单线程</strong>的语言，但是由于事件驱动的特性，非阻塞令Nodejs也具有并发的能力，这种并发并不同于多线程的并发，在实际上它是不同时的，正因为如此，他也。在常见的小程序中，对并发有着相对刚性的需求的，应该算是网页爬虫了，当抓取多个URL的时候，每一个URL响应的时间都比较长，如果使用嵌套的代码无疑是一种费时费力的方法，在Nodejs中，有很多方法可以实现对并发的控制，三种常用的如下：</p>
<ul>
<li><strong>Eventproxy</strong> ： 由国内专业选手朴灵贡献，<a href="https://github.com/JacksonTian/eventproxy" target="_blank" rel="external">github地址</a>。</li>
<li><strong>async</strong> ： 由Caolan McMahon贡献，<a href="https://github.com/caolan/async" target="_blank" rel="external">github地址</a>。</li>
<li><strong>promise</strong> ： 原来由社区提供的模块，ECMAScript6将promise规范化为一个内置对象.</li>
</ul>
<h2 id="Evenrproxy"><a href="#Evenrproxy" class="headerlink" title="Evenrproxy"></a>Evenrproxy</h2><p>EventProxy 仅仅是一个很轻量的工具，但是能够带来一种事件式编程的思维变化。有几个特点：</p>
<ul>
<li>利用事件机制解耦复杂业务逻辑</li>
<li>移除被广为诟病的深度callback嵌套问题</li>
<li>将串行等待变成并行等待，提升多异步协作场景下的执行效率</li>
<li>友好的Error handling</li>
<li>无平台依赖，适合前后端，能用于浏览器和Node.js</li>
<li>兼容CMD，AMD以及CommonJS模块环境</li>
</ul>
<p>过去的，深度嵌套的，串行的事件处理代码很不美观，如下：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> render = <span class="function"><span class="keyword">function</span> (<span class="params">template, data</span>) </span>&#123;</span><br><span class="line">  _.template(template, data);</span><br><span class="line">&#125;;</span><br><span class="line">$.get(<span class="string">"template"</span>, <span class="function"><span class="keyword">function</span> (<span class="params">template</span>) </span>&#123;</span><br><span class="line">  <span class="comment">// something</span></span><br><span class="line">  $.get(<span class="string">"data"</span>, <span class="function"><span class="keyword">function</span> (<span class="params">data</span>) </span>&#123;</span><br><span class="line">    <span class="comment">// something</span></span><br><span class="line">    $.get(<span class="string">"l10n"</span>, <span class="function"><span class="keyword">function</span> (<span class="params">l10n</span>) </span>&#123;</span><br><span class="line">      <span class="comment">// something</span></span><br><span class="line">      render(template, data, l10n);</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>
<p>三个事件template，data和l10n处于一个三层嵌套之中，如果采用eventproxy的话，所有的事件处理的逻辑代码会被分开，然后eventproxy提供一个create方法，将所有并发的事件注册到create之后分别处理，这样，当所有事件处理完成后，eventproxy就会触发，代码如下：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> ep = EventProxy.create(<span class="string">"template"</span>, <span class="string">"data"</span>, <span class="string">"l10n"</span>, <span class="function"><span class="keyword">function</span> (<span class="params">template, data, l10n</span>) </span>&#123;</span><br><span class="line">  _.template(template, data, l10n);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">$.get(<span class="string">"template"</span>, <span class="function"><span class="keyword">function</span> (<span class="params">template</span>) </span>&#123;</span><br><span class="line">  <span class="comment">// something</span></span><br><span class="line">  ep.emit(<span class="string">"template"</span>, template);</span><br><span class="line">&#125;);</span><br><span class="line">$.get(<span class="string">"data"</span>, <span class="function"><span class="keyword">function</span> (<span class="params">data</span>) </span>&#123;</span><br><span class="line">  <span class="comment">// something</span></span><br><span class="line">  ep.emit(<span class="string">"data"</span>, data);</span><br><span class="line">&#125;);</span><br><span class="line">$.get(<span class="string">"l10n"</span>, <span class="function"><span class="keyword">function</span> (<span class="params">l10n</span>) </span>&#123;</span><br><span class="line">  <span class="comment">// something</span></span><br><span class="line">  ep.emit(<span class="string">"l10n"</span>, l10n);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>
<p>以上的代码其实并不能体现eventproxy的优势，两者的代码对比起来其实并不差太多，但是当事件变得非常多的时候就会有作用了。比如一个爬虫：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> eventproxy = <span class="built_in">require</span>(<span class="string">'eventproxy'</span>);</span><br><span class="line"><span class="keyword">var</span> superagent = <span class="built_in">require</span>(<span class="string">'superagent'</span>);</span><br><span class="line"><span class="keyword">var</span> cheerio = <span class="built_in">require</span>(<span class="string">'cheerio'</span>);</span><br><span class="line"><span class="keyword">var</span> url = <span class="built_in">require</span>(<span class="string">'url'</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> targetUrl = <span class="string">'https://segmentfault.com/'</span>;</span><br><span class="line"></span><br><span class="line">superagent.get(targetUrl)</span><br><span class="line">  .end(<span class="function"><span class="keyword">function</span> (<span class="params">err, res</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (err) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="built_in">console</span>.error(err);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">var</span> topicUrls = [];</span><br><span class="line">    <span class="keyword">var</span> $ = cheerio.load(res.text);</span><br><span class="line">    $(<span class="string">'.stream-list .title a'</span>).each(<span class="function"><span class="keyword">function</span> (<span class="params">idx, element</span>) </span>&#123;</span><br><span class="line">      <span class="keyword">var</span> $element = $(element);</span><br><span class="line">      <span class="keyword">var</span> href = url.resolve(targetUrl, $element.attr(<span class="string">'href'</span>));</span><br><span class="line">      topicUrls.push(href);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> ep = <span class="keyword">new</span> eventproxy();</span><br><span class="line"></span><br><span class="line">    ep.after(<span class="string">'topic_html'</span>, topicUrls.length, <span class="function"><span class="keyword">function</span> (<span class="params">topics</span>) </span>&#123;</span><br><span class="line">      topics = topics.map(<span class="function"><span class="keyword">function</span> (<span class="params">topicPair</span>) </span>&#123;</span><br><span class="line">        <span class="keyword">var</span> topicUrl = topicPair[<span class="number">0</span>];</span><br><span class="line">        <span class="keyword">var</span> topicHtml = topicPair[<span class="number">1</span>];</span><br><span class="line">        <span class="keyword">var</span> $ = cheerio.load(topicHtml);</span><br><span class="line">        <span class="keyword">return</span> (&#123;</span><br><span class="line">          title: $(<span class="string">'.title'</span>).text().trim(),</span><br><span class="line">          href: topicUrl,</span><br><span class="line">          comment1: $(<span class="string">'.qustion p'</span>).text().trim(),</span><br><span class="line">        &#125;);</span><br><span class="line">      &#125;);</span><br><span class="line"></span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'final:'</span>);</span><br><span class="line">      <span class="built_in">console</span>.log(topics);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    topicUrls.forEach(<span class="function"><span class="keyword">function</span> (<span class="params">topicUrl</span>) </span>&#123;</span><br><span class="line">      superagent.get(topicUrl)</span><br><span class="line">        .end(<span class="function"><span class="keyword">function</span> (<span class="params">err, res</span>) </span>&#123;</span><br><span class="line">          <span class="keyword">var</span> count = <span class="number">0</span>;</span><br><span class="line">          <span class="built_in">console</span>.log(<span class="string">'fetch '</span> + topicUrl + <span class="string">' successful'</span>);</span><br><span class="line">          <span class="keyword">if</span> (res) &#123;</span><br><span class="line">            <span class="comment">// console.log(res.text);</span></span><br><span class="line">            ep.emit(<span class="string">'topic_html'</span>, [topicUrl, res.text]);</span><br><span class="line">            <span class="built_in">console</span>.log(count++);</span><br><span class="line">          &#125;;</span><br><span class="line"></span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;);</span><br></pre></td></tr></table></figure>
<p>以上是一个对segmentfault的爬虫，爬取首页的主题帖及其主题作者的信息，可以看出来，加入我们串行的写这些代码，需要很深的嵌套，尽管在底层实现上，串行的写法也可以使用回调函数实现和eventproxy类似的只要所有时间都完成即执行回调代码的功能，但是从代码的整洁度，解耦性上，五一采用了eventproxy的代码会更胜一筹。备注：以上代码单独运行时会有问题，因为segmentfault会将短时间内的多次http请求视为非法，不过cnode社区和豆瓣应该可以，稍微改动即可有运行结果。</p>
<h2 id="async"><a href="#async" class="headerlink" title="async"></a>async</h2><p>这个库的功能和目标要是提供流程控制的通用模块，async的内容分为三部分：</p>
<ul>
<li>流程控制：简化十种常见流程的处理</li>
<li>集合处理：如何使用异步操作处理集合中的数据</li>
<li>工具类：几个常用的工具类</li>
</ul>
<p>处理并发事件属于流程控制这部分的API。其用于并发处理的方法为<code>parallel(tasks, [callback])</code> 的功能是将所有注册的函数进行伪并发的处理，如下：<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">async</span>.parallel([</span><br><span class="line">    <span class="function"><span class="keyword">function</span>(<span class="params">callback</span>)</span>&#123;</span><br><span class="line">        setTimeout(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">            callback(<span class="literal">null</span>, <span class="string">'one'</span>);</span><br><span class="line">        &#125;, <span class="number">200</span>);</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="function"><span class="keyword">function</span>(<span class="params">callback</span>)</span>&#123;</span><br><span class="line">        setTimeout(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">            callback(<span class="literal">null</span>, <span class="string">'two'</span>);</span><br><span class="line">        &#125;, <span class="number">100</span>);</span><br><span class="line">    &#125;</span><br><span class="line">],</span><br><span class="line"><span class="comment">// optional callback</span></span><br><span class="line"><span class="function"><span class="keyword">function</span>(<span class="params">err, results</span>)</span>&#123;</span><br><span class="line">    <span class="comment">// the results array will equal ['one','two'] even though</span></span><br><span class="line">    <span class="comment">// the second function had a shorter timeout.</span></span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// an example using an object instead of an array</span></span><br><span class="line"><span class="keyword">async</span>.parallel(&#123;</span><br><span class="line">    one: <span class="function"><span class="keyword">function</span>(<span class="params">callback</span>)</span>&#123;</span><br><span class="line">        setTimeout(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">            callback(<span class="literal">null</span>, <span class="number">1</span>);</span><br><span class="line">        &#125;, <span class="number">200</span>);</span><br><span class="line">    &#125;,</span><br><span class="line">    two: <span class="function"><span class="keyword">function</span>(<span class="params">callback</span>)</span>&#123;</span><br><span class="line">        setTimeout(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">            callback(<span class="literal">null</span>, <span class="number">2</span>);</span><br><span class="line">        &#125;, <span class="number">100</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;,</span><br><span class="line"><span class="function"><span class="keyword">function</span>(<span class="params">err, results</span>) </span>&#123;</span><br><span class="line">    <span class="comment">// results is now equals to: &#123;one: 1, two: 2&#125;</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></p>
<p>在原文中有语句话<code>is about kicking-off I/O tasks in parallel, not about parallel execution of code.</code>，说的是async的<code>paralle</code>方法的执行方式，即开球式的执行方式，所有的代码和方法都立即执行，而不是一种并发的代码执行。这里可能有点绕，实际上就是上边的代码的解释的，即便是设置了定时器，其回调函数也是迅速被执行的，也就是说，先注册的函数会被先执行，于是结果就像代码中提到的一样，而并不是我们传统的事件驱动逻辑所描述的。这有点像按照顺序执行，但是实际上是并行的，因为本身nodejs就是并行的。<br>同时，async还提供了非常实用的<code>map/reduce</code>方法集，可以实现之前本文中提到的那个爬虫的效果，示例代码如下：<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> <span class="keyword">async</span> = <span class="built_in">require</span>(<span class="string">'async'</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> concurrencyCount = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">var</span> fetchUrl = <span class="function"><span class="keyword">function</span> (<span class="params">url, callback</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> delay = <span class="built_in">parseInt</span>((<span class="built_in">Math</span>.random() * <span class="number">10000000</span>) % <span class="number">2000</span>, <span class="number">10</span>);</span><br><span class="line">  concurrencyCount++;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">'现在的并发数是'</span>, concurrencyCount, <span class="string">'，正在抓取的是'</span>, url, <span class="string">'，耗时'</span> + delay + <span class="string">'毫秒'</span>);</span><br><span class="line">  setTimeout(<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">    concurrencyCount--;</span><br><span class="line">    callback(<span class="literal">null</span>, url + <span class="string">' html content'</span>);</span><br><span class="line">  &#125;, delay);</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> urls = [];</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; <span class="number">30</span>; i++) &#123;</span><br><span class="line">  urls.push(<span class="string">'http://datasource_'</span> + i);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span>.mapLimit(urls, <span class="number">5</span>, <span class="function"><span class="keyword">function</span> (<span class="params">url, callback</span>) </span>&#123;</span><br><span class="line">  fetchUrl(url, callback);</span><br><span class="line">&#125;, <span class="function"><span class="keyword">function</span> (<span class="params">err, result</span>) </span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">'final:'</span>);</span><br><span class="line">  <span class="built_in">console</span>.log(result);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></p>
<p>其中<code>mapLimit</code>方法就是带有数量限制的map方法，包括<code>filter</code>,<code>reduce</code>,<code>iteraitor</code>等等方法也都分别可以用于对多个请求进行处理，用法和javascript本身提供的方法的原理相同。除此之外，async还有用于串行连接的<code>series</code>方法，用于类似于<code>reduce</code>的<code>waterfall</code>方法，前一个函数执行的结果将会作为后一个函数的输入，以及可以实现按照函数间的依赖进行自动执行的<code>auto</code>方法。</p>
<h2 id="Promise"><a href="#Promise" class="headerlink" title="Promise"></a>Promise</h2><p>准确的说，Promise和前两者并不是相同的东西，Promise是异步编程的一种解决方案，比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现，ES6将其写进了语言标准，统一了用法，原生提供了Promise对象。</p>
<p>Promise 对象用于延迟(deferred) 计算和异步(asynchronous ) 计算.。一个Promise对象代表着一个还未完成，但预期将来会完成的操作。</p>
<p>promise的执行过程如下图：</p>
<p><img src="https://mdn.mozillademos.org/files/8633/promises.png" alt="Promise的执行"></p>
<p>浏览器端的例子如下：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> promiseCount = <span class="number">0</span>;</span><br><span class="line">   <span class="function"><span class="keyword">function</span> <span class="title">testPromise</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">       <span class="keyword">var</span> thisPromiseCount = ++promiseCount;</span><br><span class="line"></span><br><span class="line">       <span class="keyword">var</span> log = <span class="built_in">document</span>.getElementById(<span class="string">'log'</span>);</span><br><span class="line">       log.insertAdjacentHTML(<span class="string">'beforeend'</span>, thisPromiseCount + <span class="string">') 开始(同步代码开始)&lt;br/&gt;'</span>);</span><br><span class="line"></span><br><span class="line">       <span class="comment">// 我们创建一个新的promise: 然后用'result'字符串解决这个promise (3秒后)</span></span><br><span class="line">       <span class="keyword">var</span> p1 = <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="keyword">function</span> (<span class="params">resolve, reject</span>) </span>&#123;</span><br><span class="line">           <span class="comment">// 解决函数带着解决（resolve）或拒绝（reject）promise的能力被执行</span></span><br><span class="line">           log.insertAdjacentHTML(<span class="string">'beforeend'</span>, thisPromiseCount + <span class="string">') Promise开始(异步代码开始)&lt;br/&gt;'</span>);</span><br><span class="line"></span><br><span class="line">           <span class="comment">// 这只是个创建异步解决的示例</span></span><br><span class="line">           <span class="built_in">window</span>.setTimeout(<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">               <span class="comment">// 我们满足（fullfil）了这个promise!</span></span><br><span class="line">               resolve(thisPromiseCount)</span><br><span class="line">           &#125;, <span class="built_in">Math</span>.random() * <span class="number">2000</span> + <span class="number">1000</span>);</span><br><span class="line">       &#125;);</span><br><span class="line"></span><br><span class="line">       <span class="comment">// 定义当promise被满足时应做什么</span></span><br><span class="line">       p1.then(<span class="function"><span class="keyword">function</span> (<span class="params">val</span>) </span>&#123;</span><br><span class="line">           <span class="comment">// 输出一段信息和一个值</span></span><br><span class="line">           log.insertAdjacentHTML(<span class="string">'beforeend'</span>, val + <span class="string">') Promise被满足了(异步代码结束)&lt;br/&gt;'</span>);</span><br><span class="line">       &#125;);</span><br><span class="line"></span><br><span class="line">       log.insertAdjacentHTML(<span class="string">'beforeend'</span>, thisPromiseCount + <span class="string">') 建立了Promise(同步代码结束)&lt;br/&gt;&lt;br/&gt;'</span>);</span><br><span class="line">   &#125;</span><br><span class="line">   testPromise();</span><br><span class="line">   testPromise();</span><br><span class="line">   testPromise();</span><br></pre></td></tr></table></figure>
<p>这个小例子展示了Promise的机制。每当<button>被按下时，testPromise() 函数就会被执行。该函数会创建一个用window.setTimeout在1到3秒（随机）后用‘result’字符串解决的promise。</button></p>
<p>这里通过p1.then方法的满足回调，简单的输出了promise的满足过程，这些输出显示了该方法的同步部分是如何和promise的异步解决解耦的。详细的内容可以参考<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise" target="_blank" rel="external">MDN</a></p>
<hr>
<p>[TOC]</p>
<h2 id="反馈与建议"><a href="#反馈与建议" class="headerlink" title="反馈与建议"></a>反馈与建议</h2><ul>
<li>微博：<a href="http://weibo.com/536345881" target="_blank" rel="external">@紫棠月白</a></li>
<li>邮箱：<a href="&#109;&#x61;&#x69;&#108;&#x74;&#111;&#x3a;&#122;&#104;&#x61;&#x6e;&#103;&#x77;&#97;&#121;&#122;&#106;&#x75;&#64;&#103;&#109;&#x61;&#105;&#x6c;&#x2e;&#99;&#111;&#x6d;">&#122;&#104;&#x61;&#x6e;&#103;&#x77;&#97;&#121;&#122;&#106;&#x75;&#64;&#103;&#109;&#x61;&#105;&#x6c;&#x2e;&#99;&#111;&#x6d;</a></li>
</ul>
<hr>

          
        
      
    </div>

    <footer class="post-footer">
      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </article>


    
      

  
  

  
  
  

  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
            
            
              
                
                <a class="post-title-link" href="/2016/02/21/node爬虫与eventproxy异步请求/" itemprop="url">
                  Node.js的并发控制浅析
                </a>
              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">
            <span class="post-meta-item-icon">
              <i class="fa fa-calendar-o"></i>
            </span>
            <span class="post-meta-item-text">发表于</span>
            <time itemprop="dateCreated" datetime="2016-02-21T21:31:27+08:00" content="2016-02-21">
              2016-02-21
            </time>
          </span>

          

          
            
              <span class="post-comments-count">
                &nbsp; | &nbsp;
                <a href="/2016/02/21/node爬虫与eventproxy异步请求/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count ds-thread-count" data-thread-key="2016/02/21/node爬虫与eventproxy异步请求/" itemprop="commentsCount"></span>
                </a>
              </span>
            
          

          

          
          
        </div>
      </header>
    


    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h1 id="Node-js的并发控制浅析"><a href="#Node-js的并发控制浅析" class="headerlink" title="Node.js的并发控制浅析"></a>Node.js的并发控制浅析</h1><p>@(Node.js)[并发|eventproxy|async|promise]</p>
<p>Nodejs是运行在chromeV8上的<strong>单线程</strong>的语言，但是由于事件驱动的特性，非阻塞令Nodejs也具有并发的能力，这种并发并不同于多线程的并发，在实际上它是不同时的，正因为如此，他也。在常见的小程序中，对并发有着相对刚性的需求的，应该算是网页爬虫了，当抓取多个URL的时候，每一个URL响应的时间都比较长，如果使用嵌套的代码无疑是一种费时费力的方法，在Nodejs中，有很多方法可以实现对并发的控制，三种常用的如下：</p>
<ul>
<li><strong>Eventproxy</strong> ： 由国内专业选手朴灵贡献，<a href="https://github.com/JacksonTian/eventproxy" target="_blank" rel="external">github地址</a>。</li>
<li><strong>async</strong> ： 由Caolan McMahon贡献，<a href="https://github.com/caolan/async" target="_blank" rel="external">github地址</a>。</li>
<li><strong>promise</strong> ： 原来由社区提供的模块，ECMAScript6将promise规范化为一个内置对象.</li>
</ul>
<h2 id="Evenrproxy"><a href="#Evenrproxy" class="headerlink" title="Evenrproxy"></a>Evenrproxy</h2><p>EventProxy 仅仅是一个很轻量的工具，但是能够带来一种事件式编程的思维变化。有几个特点：</p>
<ul>
<li>利用事件机制解耦复杂业务逻辑</li>
<li>移除被广为诟病的深度callback嵌套问题</li>
<li>将串行等待变成并行等待，提升多异步协作场景下的执行效率</li>
<li>友好的Error handling</li>
<li>无平台依赖，适合前后端，能用于浏览器和Node.js</li>
<li>兼容CMD，AMD以及CommonJS模块环境</li>
</ul>
<p>过去的，深度嵌套的，串行的事件处理代码很不美观，如下：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> render = <span class="function"><span class="keyword">function</span> (<span class="params">template, data</span>) </span>&#123;</span><br><span class="line">  _.template(template, data);</span><br><span class="line">&#125;;</span><br><span class="line">$.get(<span class="string">"template"</span>, <span class="function"><span class="keyword">function</span> (<span class="params">template</span>) </span>&#123;</span><br><span class="line">  <span class="comment">// something</span></span><br><span class="line">  $.get(<span class="string">"data"</span>, <span class="function"><span class="keyword">function</span> (<span class="params">data</span>) </span>&#123;</span><br><span class="line">    <span class="comment">// something</span></span><br><span class="line">    $.get(<span class="string">"l10n"</span>, <span class="function"><span class="keyword">function</span> (<span class="params">l10n</span>) </span>&#123;</span><br><span class="line">      <span class="comment">// something</span></span><br><span class="line">      render(template, data, l10n);</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>
<p>三个事件template，data和l10n处于一个三层嵌套之中，如果采用eventproxy的话，所有的事件处理的逻辑代码会被分开，然后eventproxy提供一个create方法，将所有并发的事件注册到create之后分别处理，这样，当所有事件处理完成后，eventproxy就会触发，代码如下：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> ep = EventProxy.create(<span class="string">"template"</span>, <span class="string">"data"</span>, <span class="string">"l10n"</span>, <span class="function"><span class="keyword">function</span> (<span class="params">template, data, l10n</span>) </span>&#123;</span><br><span class="line">  _.template(template, data, l10n);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">$.get(<span class="string">"template"</span>, <span class="function"><span class="keyword">function</span> (<span class="params">template</span>) </span>&#123;</span><br><span class="line">  <span class="comment">// something</span></span><br><span class="line">  ep.emit(<span class="string">"template"</span>, template);</span><br><span class="line">&#125;);</span><br><span class="line">$.get(<span class="string">"data"</span>, <span class="function"><span class="keyword">function</span> (<span class="params">data</span>) </span>&#123;</span><br><span class="line">  <span class="comment">// something</span></span><br><span class="line">  ep.emit(<span class="string">"data"</span>, data);</span><br><span class="line">&#125;);</span><br><span class="line">$.get(<span class="string">"l10n"</span>, <span class="function"><span class="keyword">function</span> (<span class="params">l10n</span>) </span>&#123;</span><br><span class="line">  <span class="comment">// something</span></span><br><span class="line">  ep.emit(<span class="string">"l10n"</span>, l10n);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>
<p>以上的代码其实并不能体现eventproxy的优势，两者的代码对比起来其实并不差太多，但是当事件变得非常多的时候就会有作用了。比如一个爬虫：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> eventproxy = <span class="built_in">require</span>(<span class="string">'eventproxy'</span>);</span><br><span class="line"><span class="keyword">var</span> superagent = <span class="built_in">require</span>(<span class="string">'superagent'</span>);</span><br><span class="line"><span class="keyword">var</span> cheerio = <span class="built_in">require</span>(<span class="string">'cheerio'</span>);</span><br><span class="line"><span class="keyword">var</span> url = <span class="built_in">require</span>(<span class="string">'url'</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> targetUrl = <span class="string">'https://segmentfault.com/'</span>;</span><br><span class="line"></span><br><span class="line">superagent.get(targetUrl)</span><br><span class="line">  .end(<span class="function"><span class="keyword">function</span> (<span class="params">err, res</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (err) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="built_in">console</span>.error(err);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">var</span> topicUrls = [];</span><br><span class="line">    <span class="keyword">var</span> $ = cheerio.load(res.text);</span><br><span class="line">    $(<span class="string">'.stream-list .title a'</span>).each(<span class="function"><span class="keyword">function</span> (<span class="params">idx, element</span>) </span>&#123;</span><br><span class="line">      <span class="keyword">var</span> $element = $(element);</span><br><span class="line">      <span class="keyword">var</span> href = url.resolve(targetUrl, $element.attr(<span class="string">'href'</span>));</span><br><span class="line">      topicUrls.push(href);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> ep = <span class="keyword">new</span> eventproxy();</span><br><span class="line"></span><br><span class="line">    ep.after(<span class="string">'topic_html'</span>, topicUrls.length, <span class="function"><span class="keyword">function</span> (<span class="params">topics</span>) </span>&#123;</span><br><span class="line">      topics = topics.map(<span class="function"><span class="keyword">function</span> (<span class="params">topicPair</span>) </span>&#123;</span><br><span class="line">        <span class="keyword">var</span> topicUrl = topicPair[<span class="number">0</span>];</span><br><span class="line">        <span class="keyword">var</span> topicHtml = topicPair[<span class="number">1</span>];</span><br><span class="line">        <span class="keyword">var</span> $ = cheerio.load(topicHtml);</span><br><span class="line">        <span class="keyword">return</span> (&#123;</span><br><span class="line">          title: $(<span class="string">'.title'</span>).text().trim(),</span><br><span class="line">          href: topicUrl,</span><br><span class="line">          comment1: $(<span class="string">'.qustion p'</span>).text().trim(),</span><br><span class="line">        &#125;);</span><br><span class="line">      &#125;);</span><br><span class="line"></span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'final:'</span>);</span><br><span class="line">      <span class="built_in">console</span>.log(topics);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    topicUrls.forEach(<span class="function"><span class="keyword">function</span> (<span class="params">topicUrl</span>) </span>&#123;</span><br><span class="line">      superagent.get(topicUrl)</span><br><span class="line">        .end(<span class="function"><span class="keyword">function</span> (<span class="params">err, res</span>) </span>&#123;</span><br><span class="line">          <span class="keyword">var</span> count = <span class="number">0</span>;</span><br><span class="line">          <span class="built_in">console</span>.log(<span class="string">'fetch '</span> + topicUrl + <span class="string">' successful'</span>);</span><br><span class="line">          <span class="keyword">if</span> (res) &#123;</span><br><span class="line">            <span class="comment">// console.log(res.text);</span></span><br><span class="line">            ep.emit(<span class="string">'topic_html'</span>, [topicUrl, res.text]);</span><br><span class="line">            <span class="built_in">console</span>.log(count++);</span><br><span class="line">          &#125;;</span><br><span class="line"></span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;);</span><br></pre></td></tr></table></figure>
<p>以上是一个对segmentfault的爬虫，爬取首页的主题帖及其主题作者的信息，可以看出来，加入我们串行的写这些代码，需要很深的嵌套，尽管在底层实现上，串行的写法也可以使用回调函数实现和eventproxy类似的只要所有时间都完成即执行回调代码的功能，但是从代码的整洁度，解耦性上，五一采用了eventproxy的代码会更胜一筹。备注：以上代码单独运行时会有问题，因为segmentfault会将短时间内的多次http请求视为非法，不过cnode社区和豆瓣应该可以，稍微改动即可有运行结果。</p>
<h2 id="async"><a href="#async" class="headerlink" title="async"></a>async</h2><p>这个库的功能和目标要是提供流程控制的通用模块，async的内容分为三部分：</p>
<ul>
<li>流程控制：简化十种常见流程的处理</li>
<li>集合处理：如何使用异步操作处理集合中的数据</li>
<li>工具类：几个常用的工具类</li>
</ul>
<p>处理并发事件属于流程控制这部分的API。其用于并发处理的方法为<code>parallel(tasks, [callback])</code> 的功能是将所有注册的函数进行伪并发的处理，如下：<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">async</span>.parallel([</span><br><span class="line">    <span class="function"><span class="keyword">function</span>(<span class="params">callback</span>)</span>&#123;</span><br><span class="line">        setTimeout(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">            callback(<span class="literal">null</span>, <span class="string">'one'</span>);</span><br><span class="line">        &#125;, <span class="number">200</span>);</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="function"><span class="keyword">function</span>(<span class="params">callback</span>)</span>&#123;</span><br><span class="line">        setTimeout(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">            callback(<span class="literal">null</span>, <span class="string">'two'</span>);</span><br><span class="line">        &#125;, <span class="number">100</span>);</span><br><span class="line">    &#125;</span><br><span class="line">],</span><br><span class="line"><span class="comment">// optional callback</span></span><br><span class="line"><span class="function"><span class="keyword">function</span>(<span class="params">err, results</span>)</span>&#123;</span><br><span class="line">    <span class="comment">// the results array will equal ['one','two'] even though</span></span><br><span class="line">    <span class="comment">// the second function had a shorter timeout.</span></span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// an example using an object instead of an array</span></span><br><span class="line"><span class="keyword">async</span>.parallel(&#123;</span><br><span class="line">    one: <span class="function"><span class="keyword">function</span>(<span class="params">callback</span>)</span>&#123;</span><br><span class="line">        setTimeout(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">            callback(<span class="literal">null</span>, <span class="number">1</span>);</span><br><span class="line">        &#125;, <span class="number">200</span>);</span><br><span class="line">    &#125;,</span><br><span class="line">    two: <span class="function"><span class="keyword">function</span>(<span class="params">callback</span>)</span>&#123;</span><br><span class="line">        setTimeout(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">            callback(<span class="literal">null</span>, <span class="number">2</span>);</span><br><span class="line">        &#125;, <span class="number">100</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;,</span><br><span class="line"><span class="function"><span class="keyword">function</span>(<span class="params">err, results</span>) </span>&#123;</span><br><span class="line">    <span class="comment">// results is now equals to: &#123;one: 1, two: 2&#125;</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></p>
<p>在原文中有语句话<code>is about kicking-off I/O tasks in parallel, not about parallel execution of code.</code>，说的是async的<code>paralle</code>方法的执行方式，即开球式的执行方式，所有的代码和方法都立即执行，而不是一种并发的代码执行。这里可能有点绕，实际上就是上边的代码的解释的，即便是设置了定时器，其回调函数也是迅速被执行的，也就是说，先注册的函数会被先执行，于是结果就像代码中提到的一样，而并不是我们传统的事件驱动逻辑所描述的。这有点像按照顺序执行，但是实际上是并行的，因为本身nodejs就是并行的。<br>同时，async还提供了非常实用的<code>map/reduce</code>方法集，可以实现之前本文中提到的那个爬虫的效果，示例代码如下：<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> <span class="keyword">async</span> = <span class="built_in">require</span>(<span class="string">'async'</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> concurrencyCount = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">var</span> fetchUrl = <span class="function"><span class="keyword">function</span> (<span class="params">url, callback</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> delay = <span class="built_in">parseInt</span>((<span class="built_in">Math</span>.random() * <span class="number">10000000</span>) % <span class="number">2000</span>, <span class="number">10</span>);</span><br><span class="line">  concurrencyCount++;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">'现在的并发数是'</span>, concurrencyCount, <span class="string">'，正在抓取的是'</span>, url, <span class="string">'，耗时'</span> + delay + <span class="string">'毫秒'</span>);</span><br><span class="line">  setTimeout(<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">    concurrencyCount--;</span><br><span class="line">    callback(<span class="literal">null</span>, url + <span class="string">' html content'</span>);</span><br><span class="line">  &#125;, delay);</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> urls = [];</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; <span class="number">30</span>; i++) &#123;</span><br><span class="line">  urls.push(<span class="string">'http://datasource_'</span> + i);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span>.mapLimit(urls, <span class="number">5</span>, <span class="function"><span class="keyword">function</span> (<span class="params">url, callback</span>) </span>&#123;</span><br><span class="line">  fetchUrl(url, callback);</span><br><span class="line">&#125;, <span class="function"><span class="keyword">function</span> (<span class="params">err, result</span>) </span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">'final:'</span>);</span><br><span class="line">  <span class="built_in">console</span>.log(result);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></p>
<p>其中<code>mapLimit</code>方法就是带有数量限制的map方法，包括<code>filter</code>,<code>reduce</code>,<code>iteraitor</code>等等方法也都分别可以用于对多个请求进行处理，用法和javascript本身提供的方法的原理相同。除此之外，async还有用于串行连接的<code>series</code>方法，用于类似于<code>reduce</code>的<code>waterfall</code>方法，前一个函数执行的结果将会作为后一个函数的输入，以及可以实现按照函数间的依赖进行自动执行的<code>auto</code>方法。</p>
<h2 id="Promise"><a href="#Promise" class="headerlink" title="Promise"></a>Promise</h2><p>准确的说，Promise和前两者并不是相同的东西，Promise是异步编程的一种解决方案，比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现，ES6将其写进了语言标准，统一了用法，原生提供了Promise对象。</p>
<p>Promise 对象用于延迟(deferred) 计算和异步(asynchronous ) 计算.。一个Promise对象代表着一个还未完成，但预期将来会完成的操作。</p>
<p>promise的执行过程如下图：</p>
<p><img src="https://mdn.mozillademos.org/files/8633/promises.png" alt="Promise的执行"></p>
<p>浏览器端的例子如下：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> promiseCount = <span class="number">0</span>;</span><br><span class="line">   <span class="function"><span class="keyword">function</span> <span class="title">testPromise</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">       <span class="keyword">var</span> thisPromiseCount = ++promiseCount;</span><br><span class="line"></span><br><span class="line">       <span class="keyword">var</span> log = <span class="built_in">document</span>.getElementById(<span class="string">'log'</span>);</span><br><span class="line">       log.insertAdjacentHTML(<span class="string">'beforeend'</span>, thisPromiseCount + <span class="string">') 开始(同步代码开始)&lt;br/&gt;'</span>);</span><br><span class="line"></span><br><span class="line">       <span class="comment">// 我们创建一个新的promise: 然后用'result'字符串解决这个promise (3秒后)</span></span><br><span class="line">       <span class="keyword">var</span> p1 = <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="keyword">function</span> (<span class="params">resolve, reject</span>) </span>&#123;</span><br><span class="line">           <span class="comment">// 解决函数带着解决（resolve）或拒绝（reject）promise的能力被执行</span></span><br><span class="line">           log.insertAdjacentHTML(<span class="string">'beforeend'</span>, thisPromiseCount + <span class="string">') Promise开始(异步代码开始)&lt;br/&gt;'</span>);</span><br><span class="line"></span><br><span class="line">           <span class="comment">// 这只是个创建异步解决的示例</span></span><br><span class="line">           <span class="built_in">window</span>.setTimeout(<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">               <span class="comment">// 我们满足（fullfil）了这个promise!</span></span><br><span class="line">               resolve(thisPromiseCount)</span><br><span class="line">           &#125;, <span class="built_in">Math</span>.random() * <span class="number">2000</span> + <span class="number">1000</span>);</span><br><span class="line">       &#125;);</span><br><span class="line"></span><br><span class="line">       <span class="comment">// 定义当promise被满足时应做什么</span></span><br><span class="line">       p1.then(<span class="function"><span class="keyword">function</span> (<span class="params">val</span>) </span>&#123;</span><br><span class="line">           <span class="comment">// 输出一段信息和一个值</span></span><br><span class="line">           log.insertAdjacentHTML(<span class="string">'beforeend'</span>, val + <span class="string">') Promise被满足了(异步代码结束)&lt;br/&gt;'</span>);</span><br><span class="line">       &#125;);</span><br><span class="line"></span><br><span class="line">       log.insertAdjacentHTML(<span class="string">'beforeend'</span>, thisPromiseCount + <span class="string">') 建立了Promise(同步代码结束)&lt;br/&gt;&lt;br/&gt;'</span>);</span><br><span class="line">   &#125;</span><br><span class="line">   testPromise();</span><br><span class="line">   testPromise();</span><br><span class="line">   testPromise();</span><br></pre></td></tr></table></figure>
<p>这个小例子展示了Promise的机制。每当button被按下时，testPromise() 函数就会被执行。该函数会创建一个用window.setTimeout在1到3秒（随机）后用‘result’字符串解决的promise。</p>
<p>这里通过p1.then方法的满足回调，简单的输出了promise的满足过程，这些输出显示了该方法的同步部分是如何和promise的异步解决解耦的。详细的内容可以参考<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise" target="_blank" rel="external">MDN</a></p>
<hr>
<p>[TOC]</p>
<h2 id="反馈与建议"><a href="#反馈与建议" class="headerlink" title="反馈与建议"></a>反馈与建议</h2><ul>
<li>微博：<a href="http://weibo.com/536345881" target="_blank" rel="external">@紫棠月白</a></li>
<li>邮箱：<a href="&#x6d;&#97;&#105;&#x6c;&#116;&#x6f;&#58;&#122;&#104;&#97;&#110;&#103;&#x77;&#x61;&#121;&#x7a;&#106;&#117;&#64;&#x67;&#x6d;&#x61;&#105;&#108;&#x2e;&#x63;&#111;&#x6d;">&#122;&#104;&#97;&#110;&#103;&#x77;&#x61;&#121;&#x7a;&#106;&#117;&#64;&#x67;&#x6d;&#x61;&#105;&#108;&#x2e;&#x63;&#111;&#x6d;</a></li>
</ul>
<hr>

          
        
      
    </div>

    <footer class="post-footer">
      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </article>


    
      

  
  

  
  
  

  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
            
            
              
                
                <a class="post-title-link" href="/2016/02/19/powershell初探/" itemprop="url">
                  powershell初探
                </a>
              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">
            <span class="post-meta-item-icon">
              <i class="fa fa-calendar-o"></i>
            </span>
            <span class="post-meta-item-text">发表于</span>
            <time itemprop="dateCreated" datetime="2016-02-19T02:16:00+08:00" content="2016-02-19">
              2016-02-19
            </time>
          </span>

          

          
            
              <span class="post-comments-count">
                &nbsp; | &nbsp;
                <a href="/2016/02/19/powershell初探/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count ds-thread-count" data-thread-key="2016/02/19/powershell初探/" itemprop="commentsCount"></span>
                </a>
              </span>
            
          

          

          
          
        </div>
      </header>
    


    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h3 id="powershell脚本"><a href="#powershell脚本" class="headerlink" title="powershell脚本"></a>powershell脚本</h3><p>Windows PowerShell® 是基于任务的命令行 shell 和脚本语言，专为进行系统管理而设计。在 .NET Framework 的<br>基础上构建的 Windows PowerShell可帮助 IT 专业人士和高级用户控制和自动运行 Windows 操作系统以及在<br>Windows 上运行的应用程序的管理。</p>
<p>Windows PowerShell 命令（称为 cmdlet）使你可以从命令行管理计算机。</p>
<h3 id="特点"><a href="#特点" class="headerlink" title="特点"></a>特点</h3><ul>
<li><p>最初我接触powershell时把他当做windows环境下的shell来使用，这种用法有一个很大的问题就是这使得<br>powershell看起来远远不如shell强大。</p>
</li>
<li><p>powershell与shell不同的是，powershell能够采用类似javascript的对象进行数据的传递，同时能够<br>调用windows 的COM组件。</p>
</li>
<li><p>powershell还有一套自己的API，其中有些能够实现增强的shell命令的作用，比如用于查看信息的get-这一<br>类库，其中的方法就包括获取进程信息，硬件信息等等。具体的API可以再<a href="https://technet.microsoft.com/zh-cn/library/bb978526.aspx" target="_blank" rel="external">msdn</a>上查看。</p>
</li>
</ul>
<h3 id="环境"><a href="#环境" class="headerlink" title="环境"></a>环境</h3><p>其实windows7之后的所有windows版本都已经默认自带了powershell，但是单纯的powershell并不够强大，编写powershell这么一门较为复杂的脚本<br>没有语法辅助会感到很麻烦，所以需要安装<a href="https://technet.microsoft.com/zh-cn/library/dd819514.aspx" target="_blank" rel="external">development kit</a>.</p>
<p>安装完成之后会发现ISE的语法提示做得非常好，但是第一次运行脚本的时候回出现问题，提示错误为执行策略不对，这是因为windows默认的关于<br>powershell的策略是可以执行命令但是不能执行脚本的Restricted策略，我们需要修改策略，各种策略用于不同的环境，我修改的策略是<br>RemoteSigned，这种策略意味着本地编写的脚本可以执行，而来自其他地方的脚本则需要验证签名，一般只有官方的签名才能够执行。</p>
<p>具体修改策略的命令为Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned。</p>
<p>其中可以看出，参数scope就是大多数语言都具有的作用域，ExcutionPolicy就是执行策略。</p>
<h3 id="脚本初试"><a href="#脚本初试" class="headerlink" title="脚本初试"></a>脚本初试</h3><p>为了能够更好地体现powershell的神奇，可以先尝试一些<code>黑科技</code>，首先做实现一个比较实用而且流行的功能吧，<code>找到最占内存的10个进程，然后将它们占用的内存画成一个三维饼图</code>。</p>
<p>这个功能需要用到Excel对象，这是通过COM调用的，具体的语法这里并不详细解释，具体的API都可以在上文中的msdn查阅到。</p>
<h3 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h3><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># create new excel instance</span></span><br><span class="line"> <span class="variable">$objExcel</span> = <span class="built_in">New-Object</span> -comobject Excel.Application</span><br><span class="line"> <span class="variable">$objExcel</span>.Visible = <span class="variable">$True</span></span><br><span class="line"> <span class="variable">$objWorkbook</span> = <span class="variable">$objExcel</span>.Workbooks.Add()</span><br><span class="line"> <span class="variable">$objWorksheet</span> = <span class="variable">$objWorkbook</span>.Worksheets.Item(<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line"> <span class="comment"># write information to the excel file</span></span><br><span class="line"><span class="variable">$i</span> = <span class="number">0</span></span><br><span class="line"><span class="variable">$first10</span> = (ps | sort ws -Descending | select -first <span class="number">10</span>)</span><br><span class="line"><span class="variable">$first10</span> | <span class="keyword">foreach</span> -Process &#123;<span class="variable">$i</span>++; <span class="variable">$objWorksheet</span>.Cells.Item(<span class="variable">$i</span>,<span class="number">1</span>) = <span class="variable">$_</span>.name; <span class="variable">$objWorksheet</span>.Cells.Item(<span class="variable">$i</span>,<span class="number">2</span>) = <span class="variable">$_</span>.ws&#125;</span><br><span class="line"><span class="variable">$otherMem</span> = (ps | measure ws -s).Sum - (<span class="variable">$first10</span> | measure ws -s).Sum</span><br><span class="line"><span class="variable">$objWorksheet</span>.Cells.Item(<span class="number">11</span>,<span class="number">1</span>) = <span class="string">"Others"</span>; <span class="variable">$objWorksheet</span>.Cells.Item(<span class="number">11</span>,<span class="number">2</span>) = <span class="variable">$otherMem</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># draw the pie chart</span></span><br><span class="line"><span class="variable">$objCharts</span> = <span class="variable">$objWorksheet</span>.ChartObjects()</span><br><span class="line"><span class="variable">$objChart</span> = <span class="variable">$objCharts</span>.Add(<span class="number">0</span>, <span class="number">0</span>, <span class="number">500</span>, <span class="number">300</span>)</span><br><span class="line"><span class="variable">$objChart</span>.Chart.SetSourceData(<span class="variable">$objWorksheet</span>.range(<span class="string">"A1:B11"</span>), <span class="number">2</span>)</span><br><span class="line"><span class="variable">$objChart</span>.Chart.ChartType = <span class="number">70</span></span><br><span class="line"><span class="variable">$objChart</span>.Chart.ApplyDataLabels(<span class="number">5</span>)</span><br></pre></td></tr></table></figure>
<p>要注意的是，由于和shell类似的，这个脚本其实按照命令分条执行也能够顺利运行，所以它可以既没有分割符号，也不要求严格的缩进。</p>
<p>最后是这个脚本在我的机器上运行的效果图。</p>
<p><img src="../images/process10.jpg" alt="效果图" title="Get-Process 三维饼图"></p>

          
        
      
    </div>

    <footer class="post-footer">
      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </article>


    

  </section>

  


          </div>
          


          

        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    <div class="sidebar-inner">

      

      

      <section class="site-overview sidebar-panel  sidebar-panel-active ">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
          <img class="site-author-image" itemprop="image"
               src="/images/avatar.jpg"
               alt="Zhangzju" />
          <p class="site-author-name" itemprop="name">Zhangzju</p>
          <p class="site-description motion-element" itemprop="description">A man can be destroyed but not defeated.</p>
        </div>
        <nav class="site-state motion-element">
          <div class="site-state-item site-state-posts">
            <a href="/archives">
              <span class="site-state-item-count">4</span>
              <span class="site-state-item-name">日志</span>
            </a>
          </div>
          
          

          
            <div class="site-state-item site-state-tags">
              <a href="/tags">
                <span class="site-state-item-count">3</span>
                <span class="site-state-item-name">标签</span>
              </a>
            </div>
          

        </nav>

        
          <div class="feed-link motion-element">
            <a href="/atom.xml" rel="alternate">
              <i class="fa fa-rss"></i>
              RSS
            </a>
          </div>
        

        <div class="links-of-author motion-element">
          
        </div>

        
        

        <div class="links-of-author motion-element">
          
        </div>

      </section>

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright" >
  
  &copy; 
  <span itemprop="copyrightYear">2016</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">Zhangzju</span>
</div>

<div class="powered-by">
  由 <a class="theme-link" href="http://hexo.io">Hexo</a> 强力驱动
</div>

<div class="theme-info">
  主题 -
  <a class="theme-link" href="https://github.com/iissnan/hexo-theme-next">
    NexT.Mist
  </a>
</div>



      </div>
    </footer>

    <div class="back-to-top"></div>
  </div>

  


  



  <script type="text/javascript" src="/vendors/jquery/index.js?v=2.1.3"></script>

  <script type="text/javascript" src="/vendors/fastclick/lib/fastclick.min.js?v=1.0.6"></script>

  <script type="text/javascript" src="/vendors/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>

  <script type="text/javascript" src="/vendors/velocity/velocity.min.js"></script>

  <script type="text/javascript" src="/vendors/velocity/velocity.ui.min.js"></script>

  <script type="text/javascript" src="/vendors/fancybox/source/jquery.fancybox.pack.js"></script>


  


  <script type="text/javascript" src="/js/src/utils.js?v=0.5.0"></script>

  <script type="text/javascript" src="/js/src/motion.js?v=0.5.0"></script>



  
  

  

  


  <script type="text/javascript" src="/js/src/bootstrap.js?v=0.5.0"></script>



  

  
    
  

  <script type="text/javascript">
    var duoshuoQuery = {short_name:"zhangzju"};
    (function() {
      var ds = document.createElement('script');
      ds.type = 'text/javascript';ds.async = true;
      ds.id = 'duoshuo-script';
      ds.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') + '//static.duoshuo.com/embed.js';
      ds.charset = 'UTF-8';
      (document.getElementsByTagName('head')[0]
      || document.getElementsByTagName('body')[0]).appendChild(ds);
    })();
  </script>

  
    
  





  
  

  
  


</body>
</html>
